﻿using System;
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHibernate.Criterion;
using TestBat.IModels.Domain;
using TestBat.IModels.Factories;
using TestBat.IModels.Models;
using TestBat.IModels.Repositories;
using TestBat.Models.Attributes;
using TestBat.Models.Domain;

namespace TestBat.Models.Models
{
    public class TaskFolderModel : Model, ITaskFolderModel
    {
        public TaskFolderModel(ITaskFolderRepository taskFolderRepository, ITaskRepository taskRepository,
            ITaskFactory taskFactory, ITaskFolderFactory taskFolderFactory)
        {
            this.taskFolderRepository = taskFolderRepository;
            this.taskRepository = taskRepository;
            this.taskFactory = taskFactory;
            this.taskFolderFactory = taskFolderFactory;
        }

        [Conversation]
        public IRootTaskFolder GetRootFolder()
        {
            return taskFolderRepository.GetBySubtype<RootTaskFolder>().FirstOrDefault<RootTaskFolder>();
        }

        [Conversation(ConversationEndMode.CommitAndContinue)]
        public void Save(ITaskFolder taskFolder)
        {
            // check contraints (HACK: should be extracted to another place)
            if (taskFolder is IRootTaskFolder) // folder is root
                throw new Exception();

            Validate(taskFolder);

            taskFolderRepository.MakePersistent(taskFolder);
        }

        [Conversation(ConversationEndMode.CommitAndContinue)]
        public void Delete(ITaskFolder taskFolder)
        {
            // check contraints (HACK: should be extracted to another place)
            if (taskFolder is IRootTaskFolder) // folder is root
                throw new Exception();

            // HACK: make sure parent is present in session/conversation
            taskFolder = taskFolderRepository.GetByID(taskFolder.ID);
            // END HACK
            ITaskFolder parent = (taskFolder as ILeafTaskFolder).Parent;
            (taskFolder as ILeafTaskFolder).Detach();

            taskFolderRepository.MakeTransient(taskFolder);
            taskFolderRepository.MakePersistent(parent);
        }

        [Conversation(ConversationEndMode.CommitAndContinue)]
        public ILeafTaskFolder CreateSubfolder(ITaskFolder taskFolder)
        {
            ILeafTaskFolder tf = taskFolderFactory.Create<ILeafTaskFolder>();

            tf.Parent = taskFolder;

            taskFolderRepository.MakePersistent(tf);

            return tf;
        }

        [Conversation(ConversationEndMode.CommitAndContinue)]
        public T CreateTask<T>(ITaskFolder parent) where T : ITask
        {
            // create new task
            T t = taskFactory.Create<T>();

            // HACK: make sure taskfolder is present in session/conversation
            taskFolderRepository.MakePersistent(parent);
            t.TaskFolder = parent;
            taskFolderRepository.MakePersistent(parent);
            // END HACK

            taskRepository.MakePersistent(t);

            return t;
        }

        [Conversation]
        public IList<ILeafTaskFolder> GetChildren(ITaskFolder parent)
        {
            DetachedCriteria c = DetachedCriteria.For<ITaskFolder>()
                .SetFetchMode("Children", FetchMode.Eager)
                .Add(Expression.Eq("ID", parent.ID));
            return (from t in taskFolderRepository.GetByCriteria<ITaskFolder>(c).First<ITaskFolder>().Children orderby t.Name select t).ToList<ILeafTaskFolder>();
        }

        [Conversation]
        public IList<ITask> GetTasks(ITaskFolder taskFolder)
        {
            DetachedCriteria c = DetachedCriteria.For<ITaskFolder>()
                .SetFetchMode("Tasks", FetchMode.Eager)
                .Add(Expression.Eq("ID", taskFolder.ID));
            return (from t in taskFolderRepository.GetByCriteria<ITaskFolder>(c).First<ITaskFolder>().Tasks orderby t.Name select t).ToList<ITask>();
        }

        [Conversation]
        public int GetTaskCount(ITaskFolder taskFolder)
        {
            return taskFolderRepository.GetByID(taskFolder.ID).Tasks.Count;
        }

        [Conversation]
        public void Revert(ITaskFolder taskFolder)
        {
            taskFolderRepository.Refresh(taskFolder);
        }

        private readonly ITaskFolderRepository taskFolderRepository;
        private readonly ITaskRepository taskRepository;
        private readonly ITaskFactory taskFactory;
        private readonly ITaskFolderFactory taskFolderFactory;
    }
}
